﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Globalization;
using System.Text;
using System.Windows.Forms;
using System.Collections;
using System.IO;
using System.Runtime.InteropServices;
using System.Drawing.Imaging;
using System.Security.Permissions;
using WIA;

namespace commonV2.forms
{
    public partial class scanFile : baseImageProcess
    {
        public scanFile()
        {
            InitializeComponent();
            imageFormatCb.LoadList(new FileFormats[]{FileFormats.PDF});
            imageFormatCb.Load_ImageFormat();
            ShowOptions(false);
        }

        //From http://geekswithblogs.net/tonyt/archive/2006/07/29/86608.aspx
        //I created a simple enumeration for some of the more common errors that I expected.
        private enum WiaScannerError : uint
        {
             LibraryNotInstalled = 0x80040154,
             OutputFileExists = 0x80070050,
             ScannerNotAvailable = 0x80210015,
             OperationCancelled = 0x80210064
        }

        //Instead of throwing a COMException I created a special exception class that provides an error code from the aforementioned enumeration.
        [Serializable]
        private class WiaOperationException : Exception
        {
             private WiaScannerError _errorCode;

             public WiaOperationException(WiaScannerError errorCode)
                  : base()
             {
                  ErrorCode = errorCode;
             }

             public WiaOperationException(string message, WiaScannerError errorCode)
                  : base(message)
             {
                  ErrorCode = errorCode;
             }

             public WiaOperationException(string message, Exception innerException)
                  : base(message, innerException)
             {
                  COMException comException = innerException as COMException;

                  if (comException != null)
                       ErrorCode = (WiaScannerError)comException.ErrorCode;
             }

             public WiaOperationException(string message, Exception innerException, WiaScannerError errorCode)
                  : base(message, innerException)
             {
                  ErrorCode = errorCode;
             }

             public WiaOperationException(System.Runtime.Serialization.SerializationInfo info, 
                  System.Runtime.Serialization.StreamingContext context)
                       : base(info, context)
             {
                  info.AddValue("ErrorCode", (uint)_errorCode);
             }

             public WiaScannerError ErrorCode
             {
                  get { return _errorCode; }
                  protected set { _errorCode = value; }
             }

             public override void GetObjectData(System.Runtime.Serialization.SerializationInfo info,
                  System.Runtime.Serialization.StreamingContext context)
             {
                  base.GetObjectData(info, context);
                  ErrorCode = (WiaScannerError)info.GetUInt32("ErrorCode");
             }
        }

        //The actual class I created is just for scanners, but you can adapt it to any device that supports WIA.  I've pulled out comments and removed some extra stuff like providing a friendly message for errors for the sake of brevity.
        private sealed class WiaScannerAdapter : IDisposable
        {
             private CommonDialogClass _wiaManager;
             private bool _disposed; // indicates if Dispose has been called

             public WiaScannerAdapter()
             {
             }

             ~WiaScannerAdapter()
             {
                  Dispose(false);
             }

             private CommonDialogClass WiaManager
             {
                  get { return _wiaManager; }
                  set { _wiaManager = value; }
             }

             [SecurityPermission(SecurityAction.Demand, UnmanagedCode = true)]
             public Image ScanImage(ImageFormat outputFormat, string fileName)
             {
                  if (outputFormat == null)
                       throw new ArgumentNullException("outputFormat");

                  FileIOPermission filePerm =  new FileIOPermission(FileIOPermissionAccess.AllAccess, fileName);
                  filePerm.Demand();

                  ImageFile imageObject = null;

                  try
                  {
                       if (WiaManager == null)
                            WiaManager = new CommonDialogClass();

                       imageObject =
                            WiaManager.ShowAcquireImage(WiaDeviceType.ScannerDeviceType,
                                 WiaImageIntent.ColorIntent, WiaImageBias.MinimizeSize, 
                                 outputFormat.Guid.ToString("B"), false, true, true);

                       imageObject.SaveFile(fileName);
                       return Image.FromFile(fileName);
                  }
                  catch (COMException ex)
                  {
                       string message = "Error scanning image";
                       throw new WiaOperationException(message, ex);
                  }
                  finally
                  {
                       if (imageObject != null)  Marshal.ReleaseComObject(imageObject);
                  }
             }

             public void Dispose()
             {
                  Dispose(true);
                  GC.SuppressFinalize(this);
             }

             private void Dispose(bool disposing)
             {
                  if (!_disposed)
                  {
                       if (disposing)
                       {
                            // no managed resources to cleanup
                       }

                      // cleanup unmanaged resources
                      if (_wiaManager != null)
                           Marshal.ReleaseComObject(_wiaManager);

                      _disposed = true;
                  }
             }
        }

        public override void SetLanguage()
        {
            base.SetLanguage();
            this.formatBtn.Text = language.GetString("format");
            this.fileFormatLbl.Text = language.GetString("format");
            this.closeOptionBtn.Text = language.GetString("hide");
        }

        //Calling the adapter is really easy.  Here's an example that puts the image into a picturebox:
        protected override void GetImage()
        {
            using (WiaScannerAdapter adapter = new WiaScannerAdapter())
            {
                try
                {
                    DisposeImage();
                    ImageFormat imgFormat = GetImageFormat();
                    RemoveTempFile();
                    string imageFileName = GetTempFile("." + imgFormat.ToString());
                    Image image = adapter.ScanImage(imgFormat, imageFileName);
                    emImage.Image = image;
                    this.myResultFileName = imageFileName;
                }
                catch (WiaOperationException ex)
                {
                    ErrorHandler(this,ex);
                }
            }
            return;
        }

        protected override bool DoSelect()
        {
            if (!base.DoSelect()) return false;
            if (this.myResultFileName == null)
            {
                SysLibs.ShowErrorMessage(language.GetString("invalidData"));
                return false;
            }
            if (imageFormatCb.myValue == FileFormats.PDF)
            {
                string newFileName = fileFuncs.GetTempFileName(".pdf");
                images.Image2Pdf(this.myResultFileName, newFileName);
                this.myResultFileName = newFileName;
            }
            return true;
        }

        private ImageFormat GetImageFormat()
        {
            switch(imageFormatCb.myValue) 
            {
                case FileFormats.GIF : return  ImageFormat.Png;
                case FileFormats.JPEG: return ImageFormat.Png;
                case FileFormats.TIFF: return ImageFormat.Png;
                case FileFormats.Bitmap: return ImageFormat.Png;
                case FileFormats.Icon: return ImageFormat.Icon;
                case FileFormats.PNG: return ImageFormat.Png;
                default: return  ImageFormat.Png;
            }
        }

        private void ShowOptions(bool state)
        {
            if (state)
            {
                formatBtn.Enabled = false;
                optionPnl.Visible = !formatBtn.Enabled;
                buttonPnl.Height = optionPnl.Location.Y + optionPnl.Height;
            }
            else
            {
                formatBtn.Enabled = true;
                optionPnl.Visible = !formatBtn.Enabled;
                buttonPnl.Height = getImageBtn.Location.Y + getImageBtn.Height;
            }
            this.ResizeForm();
        }

        private void formatBtn_Click(object sender, EventArgs e)
        {
            ShowOptions(true);
        }

        private void closeOptionBtn_Click(object sender, EventArgs e)
        {
            ShowOptions(false);
        }
    }
}
